我們經過十幾天的總總的了解,我們要開始實際的做第一個外掛的擴充,我本身公司裡是用到wooCommerce,所以對於寫這個的擴充都會比較多一些,這在講解起來會比較詳細些,而且較不會講錯誤人子弟XD我接下來可能挑個兩三次主題,會挑選wooCommerce那些要收錢貴姍姍(還有比較簡單一些)的外掛來做改寫,那我們今天就是這個模板Products Visibility by User Roles,那我們的目標就是達成簡單的限定用戶之餘,也能對要做出使用者限制與這個功能繼續延伸的可能性做一個探討。
在正常的使用woocommerce中,我就不加多以解釋,那麼平常大家對於自己設定是否可以開放購買,都有一定的認知,而今天是要使用hook的方式,來將商品無法購買,不過增加這一個因為是filter的關係,如果購物車中有原本的商品,是會被清空的。
add_filter('woocommerce_is_purchasable', 'go_ranger_purchasable_limt');
function go_ranger_purchasable_limt($is_purchasable,$product){
if( in_array($product->get_id(),array(621,457,833)) ) {
return false;
}else return $is_purchasable;
}
在array 之中是可以將所有要限制的產品代號來做,而我們可以加上使用者的過濾,來將特定的使用者或是role來做限制,那我們得確保使用者是否登入及是否能抓到值,而抓到在做in_array中進行判斷,那我們預設訂閱者與編輯者是沒有辦法看到我們的產品的,那我們就可以使用這個方式來做限制。
function go_ranger_get_current_user_roles() {
$roles = array();
if( is_user_logged_in() ) {
$user = wp_get_current_user();
$roles = ( array ) $user->roles;
if(in_array($roles,array('subscriber','editor'))) {
return false;
} else return true;
}else return false;
}
function go_ranger_purchasable_limt($is_purchasable,$product){
if(true === go_ranger_get_current_user_roles())return $is_purchasable;
if( in_array($product->get_id(),array(621,457,833)) ) {
return false;
}
}
這樣我們就可以做到以使用者的role,來決定誰可以看見特定的商品,而這類的應用往往出現在所謂的VVIP的使用,特別好用,但有個美中不足的是,我本來的設計是想使用is_visible來將目錄中,不需要出現的商品隱藏,想採取使用is_visble來做,不過在archieve的頁面中,使用woocommerce_product_loop_start
會讓目錄有跑版的問題,所以換了一個filter來製作,我們選定woocommerce_product_is_visible
,老實說,woocommerce的文件看似寫得很齊全,實際上你真的要查什麼東西,找不到的機率很大,不如從core去推敲會更快些。
add_filter('woocommerce_product_is_visible','go_ranger_visible_product',10,2);
function go_ranger_visible_product( $visible, $product_id ){
if(true === go_ranger_get_current_user_roles()) return $visible;
if($product_id === 6226){
return false;
} else return $visible;
}
加上這一些程式碼,並且在可以在meta中,加上要封閉的option,就可以對每一個產品做出限制了,而我們這次就不加上後台的程式碼,在寫的時候出現一點亂流,導致我測試環境掛掉查了兩小時,結果是git 因為rebose出現change log對不上找不出bug,而假設我們已經在後台做出個簡單的限制role則可以在我們後端改寫。
最後的邏輯調整成go_ranger_get_current_user_roles
回傳true就可以使用,讓上下的邏輯一至,而我們設定我們的產品id來當post id,而每一個post id都有一個相對應得visible key 來顯示裡頭顯示的函式,而我們可以看見$visible_roles
將包含該商品的被允許顯示,當然我們也可以設計成,誰不能看到,就與我們上半部寫的邏輯一至,不過我相信特定商品,應該還是少數人被允許看見的這種情況較常見,為了閱讀性go_ranger_purchasable_limt
與go_ranger_visible_product
並沒有整再一起。
add_filter('woocommerce_is_purchasable', 'go_ranger_purchasable_limt',10,2);
add_filter('woocommerce_product_is_visible','go_ranger_visible_product',10,2);
function visible_check($product_id){
return get_post_meta( $product_id, '_go_ranger_is_restrict_visible',true);
}
function go_ranger_get_current_user_roles($product_id) {
$roles = array();
$visible_roles = get_post_meta( $product_id, '_go_ranger_role_visible');
if( is_user_logged_in() ) {
$user = wp_get_current_user();
$roles = ( array ) $user->roles;
if(in_array($roles,$visible_roles)) {
return true;
} else return false;
}else return false;
}
function go_ranger_purchasable_limt($is_purchasable,$product){
if(false === visible_check()) return $is_purchasable;
if(true === go_ranger_get_current_user_roles($product->get_id())) return true;
return false;
}
function go_ranger_visible_product( $visible, $product_id ){
if(false === visible_check()) return $visible;
if(true === go_ranger_get_current_user_roles($product_id)) return true;
return false;
}
我們寫了一大段的程式碼,除了確切的不能購買以及將visible給調掉,但還是可以在搜尋或是計算有幾個產品的片段露餡,可以在pre_get_posts
與get_terms
中做更改,讓他們顯示的更正確。
那我們第二個缺的,就是下圖這樣,加入一個foreach的role清單,再將使用者加入meta來做到這個基本加入的功能,而在每一個product底下顯示則是加入add_meta_box來做到擴充:
add_action( 'add_meta_boxes' , 'go_ranger_add_meta_box' , 10 , 1);
public function go_ranger_add_meta_box( $post_type ) {
global $post;
$post_types = array('product');
$product = get_product( $post->ID );
if ( in_array( $post_type, $post_types ) && ($product->product_type == 'simple' ) ) {
add_meta_box(
'go_ranger_set_restrict'
,__( 'Go Ranger set restrict', 'woocommerce' )
,'你的模板套進去'
,$post_type
,'advanced'
,'high'
);
}
}
最後在save post打回自己的頁面,來完成這個設計,就可以簡單的完成使用user role來限制客戶的存取限制,而如果是要給特定用戶但商業邏輯並沒辦法使用role來解決,那麼在設計上可以改成get_users來做用id來確認客戶是否可以瀏覽到此產品,不過我們之中還有一項meta沒有提到,那就是get_post_meta( $product_id, '_go_ranger_is_restrict_visible')
對應的,得有個checkbox來確定是否啟動,並且才有上面那個列表的出現,conditional logical可以enqueue自己寫的JS來做,我用ultimate member的截圖來當範例。
而另外一個方式,就是增加更多的roles,不過這個可能需要使用套件來做到了,我們明天講完i18n後,再來講講如何實作多重的roles,而這個多重概念可以有幾個方向,第一個是使用meta來做出虛擬的role,並且在core get_role之類的函式做相關的取代,不過這個設定可能會有些capabilities的問題,是可以開一張表來設定roles與每個註冊的cap可以做的事情,這樣提升準確率。
而這個除了限定之外,其實對於那些惡意的admin subscriber是很有效的限制,你甚至是可以做出一個可以被搜尋到,到無法被下單的trap來做熱部署的缺口,以及寫定轉指到die 404的設定,404肯定比很多hook後,跑出來的結果還要更快速些,讓那些愛亂打人的攻擊者一堵小牆建立起來,也讓自己的購物系統(wooCommerce)更強壯些。
WooCommerce action hook
WooCommerce Code Reference
List WordPress Posts by Category
get_post_meta
Handle WooCommerce Product Settings
Add Custom Fields for WooCommerce Using Meta Box
WOOCOMMERCE HIDDEN PRODUCTS: HOW TO SET PRODUCT VISIBILITY IN YOUR STORE
2 user-friendly plugins to hide WooCommerce products